home *** CD-ROM | disk | FTP | other *** search
/ New Star Software Collection / NSS_Collection.iso / 3-170 dbase 10 for windows / 1.ima / DOC.PAK / OOPEXTEN.TXT < prev    next >
Text File  |  1993-07-26  |  22KB  |  626 lines

  1.      Copyright (c) 1991-1993 Borland International, Inc.  
  2.                     All Rights Reserved.
  3.  
  4.             THE dBASE LANGUAGE OBJECT EXTENSIONS
  5.             ------------------------------------
  6. Application programmers are facing increasingly complex
  7. programming requirements. For instance, building event-driven
  8. Windows applications often means learning new techniques and
  9. coordinating among several programmers writing many lines of
  10. source code. To make your job easier, Bladerunner has enhanced
  11. the dBASE language with new object oriented extensions.
  12.  
  13. This document introduces the object extensions and describes some
  14. of the new techniques for using them. Another file, DBLANG.WRI,
  15. contains specifications and syntax for the new extensions.
  16.  
  17. Contents
  18. --------
  19.  
  20. I.    Object Terminology
  21. II.   Who Needs Object Extensions?
  22. III.  Object-Orientated Design in dBASE
  23. IV.   Variable Scoping and Objects
  24. V.    Creating Objects
  25. VI.   Understanding Object Reference Variables
  26. VII.  Understanding Function Pointers
  27. VIII. Creating New Classes
  28. IX.   Examples
  29.  
  30. Object Terminology
  31. ------------------
  32.  
  33. Before learning how object orientation applies to dBASE, you need
  34. to become familiar with certain standard terminology of object-
  35. oriented programming. The following definitions will give you an
  36. idea of how these concepts are implemented in Bladerunner.
  37.  
  38. Object    A collection of related memory variables. Objects
  39.           consist of properties and methods. An object is an
  40.           "instance" of a class. For example, a window you
  41.           create, with DEFINE WINDOW, is an instance of the
  42.           Window class.
  43.  
  44. Class     A specification, or "recipe," for a type of
  45.           object. A class definition consists of two parts:
  46.           first, any dBASE code required for the construction of
  47.           an object, such as property assignments; second, method
  48.           declarations. Bladerunner provides many pre-defined
  49.           "stock" classes, such as Window and Menu. (The list of
  50.           stock classes appears in the on-line help.) You can also
  51.           create your own classes with the CLASS...ENDCLASS
  52.           statement.
  53.  
  54. Member    An item contained in an object. An object's
  55.           members are properties and methods.
  56.  
  57. Property  A memory variable contained in an object.
  58.           Properties define characteristics of an object, such as
  59.           size, location, or color. You can query the value of
  60.           any property, and change the value of most properties.
  61.           You can add new properties to an object with a simple
  62.           assignment statement.
  63.  
  64. Method    A subroutine, such as a function or procedure,
  65.           associated with an object through a function-pointer
  66.           variable. Methods perform actions on an object. For
  67.           example, a method can change an object's position in a
  68.           window, or determine if the value of a property is
  69.           valid. Some methods execute automatically when an event
  70.           occurs; others execute only when called explicitly.
  71.  
  72. Event     An occurrence, such as a mouse click. Events cause
  73.           methods to execute. For example, pressing the left
  74.           mouse button while pointing to a window object executes
  75.           the window's OnLeftMouseDown method.
  76.  
  77.  
  78. Who Needs Object Extensions?
  79. -------------------------------
  80.  
  81. Using traditional dBASE commands and techniques, you can easily
  82. build procedural user interfaces, where a series of cascading
  83. menu choices launch pre-defined procedures. However, these
  84. techniques are not well-suited for creating event-driven
  85. interfaces. In event-driven environments, like Windows, the user
  86. controls program flow. A user can click a button, activate a
  87. window, or select a menu choice at any time, and the program must
  88. respond to these events in whatever sequence they occur.
  89.  
  90. To help build event-driven applications, Bladerunner provides UI
  91. language extensions (described in UI_EXTEN.TXT). Using familiar
  92. dBASE-like syntax, any dBASE programmer can define UI objects,
  93. called "controls," and activate them in one or more windows.
  94.  
  95. Advanced programmers need the ability to change a control's
  96. characteristics in response to an event. For instance, after
  97. defining and displaying a window, your program might need to
  98. change the window's size, position, or color, without destroying
  99. the window and creating it again. The Bladerunner UI extensions
  100. let you change certain control characteristics using the REDEFINE
  101. commands. However, REDEFINE can't change all characteristics of a
  102. control, tell you the value of a characteristic, or add new
  103. characteristics.
  104.  
  105. Developers writing sophisticated user interfaces need the ability
  106. to change, query, and even add, any characteristic to a control.
  107. The Bladerunner object extensions make this easy.
  108.  
  109.  
  110.  
  111. Object-Oriented Design in dBASE
  112. -------------------------------
  113.  
  114. This section introduces some of the concepts behind object-
  115. oriented programming, then shows how you can apply them to dBASE.
  116. Focus on the concepts here; the details for implementing them are
  117. explained later.
  118.  
  119. Three main concepts characterize an object-oriented programming
  120. environment:
  121.  
  122. Encapsulation  Combining data with the subroutines that operate
  123.                on it to form a new structure called an object.
  124.  
  125. Inheritance    Defining a type, or class, of object and then
  126.                using it to build a hierarchy of descendant
  127.                objects, with each descendant "inheriting" the
  128.                data and subroutines of its ancestors.
  129.  
  130. Polymorphism   Giving an object in a hierarchy the ability to
  131.                implement an action that is common to all objects
  132.                in the hierarchy, in whatever way is most
  133.                appropriate for that object.
  134.  
  135. Suppose you write programs for a small business. In one of your
  136. applications, you create a window for displaying employee
  137. records, and another for displaying customer information. For
  138. each window, you store field values to memory variables for
  139. displaying and editing.
  140.  
  141. Next, suppose you want to display both windows at the same time.
  142. Doing so, you risk having employee variables conflict with
  143. variables defined for the customer information window. For
  144. instance, if you display the address for both employees and
  145. customers, you may overwrite the City, State, or Zip variables of
  146. an employee with those of a customer.
  147.  
  148. To solve this, you can encapsulate the employee data, and the
  149. subroutines for manipulating it, into an Employee object.
  150. Likewise, you can encapsulate the customer data and subroutines
  151. into a Customer object. Then, instead of displaying a regular
  152. memory variable for each address item, you display the City,
  153. State, and Zip "properties" of the Employee or Customer objects.
  154.  
  155. Encapsulation "hides" data in an object; so the properties of the
  156. Employee object can co-exist with the properties of the Customer
  157. object. When you encapsulate data into objects, you reduce the
  158. risk that one programmer's work will interfere with another's.
  159.  
  160. Next, suppose you want to create a new window for editing
  161. prospective customers who haven't yet placed an order. You need
  162. to store the same information as a customer, plus some new
  163. fields. Instead of creating a new window from scratch, you can
  164. create a Prospect object based on the Customer object. The
  165. Prospect object inherits the characteristics of the Customer
  166. object.
  167.  
  168. Inheritance is essentially programming by behavior modification.
  169. Different objects that share some common data or behavior can
  170. both inherit that information from an existing object, and then
  171. you can change only what's needed. Inheritance makes your code
  172. much easier to re-use.
  173.  
  174. Next, suppose you need to display information for both full-time
  175. and part-time employees. Both employee types need to store the
  176. same information, except that part-timers don't get vacation pay.
  177. You can start by creating a PartTime object based on the Employee
  178. object. The Employee object has a subroutine, CalculatePay(), for
  179. calculating the yearly compensation. In the PartTime object, you
  180. can override CalculatePay() with another function that excludes
  181. vacation pay. This is an example of polymorphism.
  182.  
  183. The dBASE SKIP command illustrates the benefits of polymorphism.
  184. SKIP works differently depending on the status of the current
  185. work area. If the work area is indexed, SKIP moves to the next
  186. record in the index; if a filter is set, SKIP moves to the next
  187. record meeting the filter condition. You don't need to tell SKIP
  188. about the work area; you just SKIP and it knows what to do.
  189.  
  190. Likewise, your program can retrieve the yearly compensation of an
  191. employee the same way, by invoking CalculatePay(), regardless of
  192. the type of employee. By "hiding" the implementation of an
  193. action, you are free to change the details of the implementation
  194. without requiring changes to the interface. Suppose full-timers
  195. get a quarterly bonus; you just change CalculatePay() for the
  196. Employee object. Polymorphism enhances the reusability of your
  197. code.
  198.  
  199. Variable Scoping and Objects
  200. ----------------------------
  201.  
  202. To understand how Bladerunner encapsulates variables into
  203. objects, you need to understand variable scoping. This section
  204. introduces objects as a solution to common dBASE scoping
  205. problems.
  206.  
  207. The scope of a memory variable is defined by
  208.  
  209. - the variable's lifespan; that is, under what circumstances a
  210.   variable is released or destroyed.
  211.  
  212. - the variable's visibility; that is, under what circumstances a
  213.   program can access or modify a variable.
  214.  
  215. Bladerunner offers two new ways to specify memory variable
  216. scopes. First, the new LOCAL command declares variables to be
  217. local to the procedure or function in which they are created.
  218. LOCAL variables are similar to PRIVATE, except that LOCAL
  219. variables are not visible in subsequently called routines.
  220. Second, the new STATIC command declares variables that are LOCAL
  221. in visibility but PUBLIC in lifespan.
  222.  
  223. The following table summarizes the lifespan and visibility of
  224. dBASE variable types:
  225.  
  226.           Lifespan                       Visibility
  227.           ----------------------------   -----------------------
  228. PUBLIC    Destroyed only when released   Everywhere
  229.  
  230. PRIVATE   Destroyed when creating        Creating routine, and
  231.           routine ends                   subsequent routines
  232.  
  233. LOCAL     Destroyed when creating        Creating routine only
  234.           routine ends
  235.  
  236. STATIC    Destroyed only when released   Creating routine only
  237.  
  238. You can declare LOCAL and STATIC variables in your procedural
  239. code to protect against inadvertant overwriting of data, and
  240. increase program modularity. Also, when you create objects,
  241. variables that are members of an object are automatically LOCAL
  242. in scope.
  243.  
  244.  
  245. Creating objects
  246. ----------------
  247.  
  248. Create an object using the NEW operator in a memory variable
  249. assignment statement. NEW creates a new object, and creates an
  250. "object reference" variable that refers to the object. (See
  251. "Understanding Object Reference Variables" below.) The following
  252. example creates a new Window object and makes MyWin refer to it:
  253.  
  254. MyWin = NEW Window()
  255.  
  256. Use the member access operator (.) to refer to a member of an
  257. object. The member access operator, or "dot" operator, associates
  258. members to an object much the same way an alias operator (->)
  259. associates a field with a particular table.
  260.  
  261. MyWin.Left = 200         && Move the left border to position 200.
  262. MyWin.Visible = .F.      && Make MyWin invisible
  263.  
  264. Objects are extensible. You can add new members to an object with
  265. a simple assignment statement.
  266.  
  267. MyWin.MyPropN = 123      && Adds a new property called MyPropN
  268. MyWin.MyPropC = "yo"     && Adds a new property called MyPropC
  269.  
  270. Understanding Object-Reference Variables
  271. ----------------------------------------
  272.  
  273. Traditional dBASE memory variables contain values; a numeric
  274. variable contains a numeric value. In contrast, an object-
  275. reference variable contains a reference to an object, not the
  276. object itself.
  277.  
  278. You create a new object-reference variable the same way you
  279. create other variables, with a simple assignment statement. To
  280. create a new object, however, use the NEW operator in an
  281. assignment statement.
  282.  
  283. This example demonstrates normal dBASE memory variable
  284. assignments:
  285.  
  286. X = 5               && X contains the value 5
  287. Y = X               && Y contains the value 5
  288. X = 6               && X contains the value 6
  289. ? X                 && Returns 6
  290. ? Y                 && Returns 5
  291.  
  292. Now compare the previous example to the following example, using
  293. object-reference variables:
  294.  
  295. MyWin = NEW Window() && Create a Window object and create
  296.                     && MyWin referring to the window.
  297. ? TYPE("MyWin")     && Returns "O" for object reference
  298. MyWin.X = 10        && Add new property X
  299. MyWin.Y = 20        && Add new property Y
  300. YourWin = MyWin     && MyWin and YourWin both refer to
  301.                     && the same window
  302. ? YourWin.X         && Returns 10
  303. YourWin.Y = 30      && Changes property Y to 30
  304. ? YourWin.Y         && Returns 30
  305. ? MyWin.Y           && Returns 30
  306. YourWin = "text"    && YourWin is now a normal char variable
  307. ? MyWin.Y           && Still returns 30
  308. MyWin = "text"      && MyWin is now a normal char variable
  309.                     && The window object is destroyed
  310.  
  311. The previous example demonstrates three important points about
  312. object-reference variables:
  313.  
  314. - More than one object-reference variable can refer to the same
  315.   object.
  316.  
  317. - When you change an object, all references to the object reflect
  318.   the change.
  319.  
  320. - An object exists as long as an object-reference variable refers
  321.   to it. When you release or re-assign all object-reference
  322.   variables referring to an object, the object is destroyed.
  323.  
  324. You work with object-reference variables the same way you work
  325. with other memory variables. For instance, you can pass them as
  326. parameters, return them as function results, and store them in
  327. arrays.
  328.  
  329. Understanding Function Pointers
  330. -------------------------------
  331.  
  332. A method is a subroutine associated with an object through a
  333. function pointer variable, a new variable type. Function pointers
  334. refer indirectly to a function. They can be copied, passed as
  335. parameters, returned as values from functions, and used in the
  336. same way as traditional variables.
  337.  
  338. Function pointers call functions indirectly using the call
  339. operator "()". For example:
  340.  
  341. pFunc = Ten         && Assigns Function Ten to pFunc
  342. ? pFunc()           && Returns 10
  343.  
  344. Function Ten
  345.      RETURN 10
  346.  
  347.  
  348. Creating New Classes
  349. --------------------
  350.  
  351. You can define a new class using the CLASS...ENDCLASS statement.
  352. The following example defines a class with two properties,
  353. creates an object of that class, and queries the property values:
  354.  
  355. X = NEW Numbers()        && Creates a new Numbers object
  356. ? X.Ten                  && Returns 10
  357. ? X.Twenty               && Returns 20
  358.  
  359. CLASS Numbers
  360.      MEMBER Ten, Twenty
  361.      Ten = 10
  362.      Twenty = 20
  363. ENDCLASS
  364.  
  365. Using MEMBER or.This to Reference Properties
  366.  
  367. The MEMBER statement in class definitions declares properties.
  368. Bladerunner also provides an alternate syntax for referencing
  369. properties in classes without explicitly declaring them. To
  370. reference properties not declared in a MEMBER statement, preface
  371. the property name with "This.".
  372.  
  373. This. acts like a place holder for the object name created from
  374. the class.
  375.  
  376. The following two class definitions are semantically identical:
  377.  
  378. A = NEW Square2()
  379. A.Num = 5
  380. ? A.Value()         && Returns 25
  381.  
  382. CLASS Square1
  383.      MEMBER Num
  384.      Num = 0
  385.      FUNCTION Value
  386.           RETURN Num * Num
  387. ENDCLASS
  388.  
  389. CLASS Square2
  390.      This.Num = 0
  391.      FUNCTION Value
  392.           RETURN This.Num * This.Num
  393. ENDCLASS
  394.  
  395.  
  396. Defining and Passing Parameters
  397.  
  398. You define and pass parameters for classes by placing the
  399. parameters in parentheses at the end of the class name.
  400. Parameters you pass are LOCAL in scope. The following example
  401. defines a class, Square, and passes a parameter when creating a
  402. Square object:
  403.  
  404. X = NEW Square(10)  && Creates a new Square object
  405. ? X.SquareNum       && Returns 100
  406. Y = NEW Square(5)   && Creates a new Square object
  407. ? Y.SquareNum       && Returns 25
  408.  
  409. CLASS Square(n)
  410.      MEMBER Num, SquareNum
  411.      Num = n
  412.      SquareNum = n*n
  413. ENDCLASS
  414.  
  415. Note: In this Alpha release, declaring parameters in parentheses
  416. is not implemented. You can instead declare parameters with a
  417. PARAMETERS statement as follows:
  418.  
  419. CLASS SQUARE
  420.      PARAMETERS n
  421. ENDCLASS
  422.  
  423. Defining and calling methods
  424.  
  425. You define methods for a class using a FUNCTION declaration
  426. within the class definition. Follow the same rules for declaring
  427. normal dBASE UDFs.
  428.  
  429. In the previous Square example, the value of property X.SquareNum
  430. is computed when you create the object. By declaring Value as a
  431. method instead of a property, you can compute Value at any time.
  432. The following example demonstrates this:
  433.  
  434. X = NEW Square2()   && Create a new Square2 object
  435. X.Num = 5           && Change the value of Num
  436. ? X.Square()        && Returns 25
  437. X.Num = 6           && Change the value of Num again
  438. ? X.Square()        && Returns 36
  439.  
  440. CLASS Square2
  441.      MEMBER num
  442.      Num = 0
  443.      FUNCTION SquareNum
  444.           RETURN Num * Num
  445. ENDCLASS
  446.  
  447. Note: If you assign the same name to a method and a property, the
  448. property is assumed in expressions. Internally, Bladerunner
  449. treats methods and properties the same; a method is a property
  450. whose data type is function-pointer.
  451.  
  452. This example assigns the name Ten to both a method and a
  453. property. Notice the return values:
  454.  
  455. Function Ten
  456.      RETURN 10
  457. Ten = 10
  458. pFunc = Ten    && assigns value 10 to pFunc
  459. ? pFunc()      && ERROR: data type mismatch
  460.  
  461. A subroutine can serve as a method for more than one object. The
  462. following example demonstrates this:
  463.  
  464. O = NEW Object()
  465. O.x = 10
  466. O.addOne = FuncAddOne
  467. ? O.addOne()             && Returns '11'
  468. ? O.x                    && Returns '11'
  469. Y = NEW Object()
  470. Y.x =30
  471. Y.z = FuncAddOne
  472. ? Y.z()                  && Returns '31'
  473. FUNCTION FuncAddOne
  474.      this.x = this.x + 1
  475.      RETURN this.x
  476.  
  477.  
  478. Examples
  479. --------
  480.  
  481. Creating a class based on another class - Inheritance
  482.  
  483. You can create a class that is derived from, or "inherits," the
  484. members of another class. The parent class can be a stock class,
  485. such as Window, or a class you previously created. This technique
  486. is called sub-classing and demonstrates the concept of
  487. inheritance. Subclasses inherit all properties and methods of the
  488. parent from which they are derived.
  489.  
  490. Use the OF option in the CLASS definition statement to specify
  491. the parent class from which to inherit members. The following
  492. example defines a class called Parent, and derives another class
  493. from Parent. The Derived class inherits all the members of
  494. Parent, and adds a few more.
  495.  
  496. b = NEW Parent()         && prints 'first '
  497. ? b.X                    && prints 10
  498. ? b.Y                    && prints 20
  499.  
  500. d = NEW Derived()        && prints 'first second'
  501. ? d.X                    && prints 10
  502. ? d.Y                    && prints 20
  503. ? d.Z                    && prints 100
  504.  
  505. CLASS Parent
  506.      MEMBER X, Y
  507.      ? "first "
  508.      X = 10
  509.      Y = 20
  510. ENDCLASS
  511.  
  512. CLASS Derived OF Parent
  513.      MEMBER Z
  514.      ?? "second"
  515.      Z = 100
  516. ENDCLASS
  517.  
  518. Overriding Parent Members - Polymorphism
  519.  
  520. When you derive a new class from a parent class, you can override
  521. parent members by simply re-initializing the variables or re-
  522. declaring the subroutines.
  523.  
  524. The technique of overriding parent members is an example of
  525. polymorphism. Polymorphism lets you treat similar objects in a
  526. uniform fashion.
  527.  
  528. This example defines a Parent class and derives a class from
  529. Parent, overriding one of Parent's methods:
  530.  
  531. A = NEW Parent()
  532. B = NEW Derived()
  533. ? A.One()                     && Prints 'Parent 1'
  534. ? A.Two()                     && Prints 'Parent 2'
  535. ? B.One()                     && Prints 'Parent 1'
  536. ? B.Two()                     && Prints 'Derived 2'
  537.  
  538. CLASS Parent
  539.      FUNCTION One
  540.           RETURN "Parent 1"
  541.      FUNCTION Two
  542.           RETURN "Parent 2"
  543. ENDCLASS
  544.  
  545. CLASS Derived OF Parent
  546.      FUNCTION Two             && Override Method Two
  547.           RETURN "Derived 2"
  548. ENDCLASS
  549.  
  550. Arrays are Objects
  551.  
  552. An array is a homogenous collection of variables; an object is a
  553. heterogeneous collection.
  554.  
  555. Arrays are a kind of object.  Arrays use the index operator to
  556. refer to contents.  Arrays also have properties. An array has the
  557. two built-in properties, size and dimensions. Arrays are objects,
  558. so variables that refer to arrays are of type object reference.
  559. More than one variable can refer to the same array.
  560.  
  561. decl a[10]
  562. ? a.size            && prints 10
  563. ? a[1]              && prints false
  564. a[1] = 10
  565. b = a               && b and a refer to the same array
  566. ? b[1]              && prints 10
  567. b[1] = 20
  568. ? a[2]              && prints 20
  569. ? a.fill("hello")
  570. ? a[4]              && prints 'hello'
  571.  
  572. Like all other objects, arrays are extensible.  Variables can be
  573. added to arrays via assignment.  For example:
  574.  
  575. decl a[10]
  576. a.myprop = "hello"  && add variable 'myprop' to
  577. ? a.myprop          && prints "hello"
  578.  
  579. Passing Properties by Reference
  580.  
  581. Pass properties by reference the same way you pass other memory
  582. variables. You can also pass array elements by reference.
  583.  
  584. O = NEW Object()
  585. O.X = 20
  586. DO Func WITH O.X
  587. ? O.X                    && prints 30
  588.  
  589. PROCEDURE Func
  590.      PARAMETERS Y
  591.      Y = Y + 10
  592.      RETURN
  593.  
  594. Returning Object-Reference Variables in Functions
  595.  
  596. Object-reference is a valid return type for a function. For
  597. example:
  598.  
  599. O = MakeObject()    && Creates a new object
  600. ? O.X                    && Returns 10
  601.  
  602. FUNCTION MakeObject
  603.      PRIVATE x
  604.      x = NEW Object()
  605.      x.x = 10
  606.      RETURN x       && Returns an object-reference var
  607.  
  608. Passing Parameters to Base Classes
  609.  
  610. You can pass parameters to base classes by including them in
  611. parenthesis after the class name. For example:
  612.  
  613. NOTE: The following code will not execute in this Alpha release.
  614.  
  615. CLASS MyCube(n) OF MySquare(n)
  616.      MEMBER CubeValue
  617.      CubeValue = Num * Square
  618. ENDCLASS
  619.  
  620. CLASS MySquare(n)
  621.      MEMBER Num, Square
  622.      Num = n
  623.      Square = n*n
  624. ENDCLASS
  625.  
  626.